package com.cbianc.creation.factory

import com.cbianc.creation.factory.module.ConcreteFactory2
import com.cbianc.creation.factory.module.Product
import org.w3c.dom.Document
import org.w3c.dom.Node
import org.w3c.dom.NodeList
import java.io.File
import javax.xml.parsers.DocumentBuilderFactory

/*
优点：
* 用户只需要知道具体工厂的名称就可得到所要的产品，无须知道产品的具体创建过程。
    灵活性增强，对于新产品的创建，只需多写一个相应的工厂类。
    典型的解耦框架。高层模块只需要知道产品的抽象类，无须关心其他实现类，满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点：
    类的个数容易过多，增加复杂度
    增加了系统的抽象性和理解难度
    抽象产品只能生产一种产品，此弊端可使用抽象工厂模式解决。
应用场景：
    客户只知道创建产品的工厂名，而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
    创建对象的任务由多个具体子工厂中的某一个完成，而抽象工厂只提供创建产品的接口。
    客户不关心创建产品的细节，只关心产品的品牌
* */
/*
结构：
    抽象工厂（接口）提供了厂品的生成方法 ==》具体工厂（实现类）
    抽象产品（接口）==》具体产品（实现类）
 */

object AbstractFactoryTest {
    @JvmStatic
    fun main(args: Array<String>) {
        try {
            val af = ConcreteFactory2() //    抽象产品只能生产一种产品，此弊端可使用抽象工厂模式解决。

            val a: Product = af.newProduct()//  客户只知道创建产品的工厂名，而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
            a.show()
        } catch (e: Exception) {
            println(e.message)
        }
    }
}


internal object ReadXML1 {
    //创建文档对象
//获取包含类名的文本节点
//System.out.println("新类名："+cName);
//通过类名生成实例对象并将其返回
//该方法用于从XML配置文件中提取具体类类名，并返回一个实例对象
    val `object`: Any?
        get() = try {
            //创建文档对象
            val dFactory = DocumentBuilderFactory.newInstance()
            val builder = dFactory.newDocumentBuilder()
            val doc: Document
            doc = builder.parse(File("src/FactoryMethod/config1.xml"))
            //获取包含类名的文本节点
            val nl: NodeList = doc.getElementsByTagName("className")
            val classNode: Node = nl.item(0).firstChild
            val cName = "FactoryMethod." + classNode.getNodeValue()
            //System.out.println("新类名："+cName);
            //通过类名生成实例对象并将其返回
            val c = Class.forName(cName)
            c.newInstance()
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            null
        }
}